/*  
CGATEAPP.C  

Copyright   (C)   1997   Prasad   Dabak   and   Sandeep   Phadke   and   Milind   Borate  

Sample   application   which   uses   CALLGATE.DLL   API   for   creating   callgates  
*/  

#include   <windows.h>  
#include   <stdio.h>  
#include   "gate.h"  

/*   Declare   the   function   present   in   RING0.ASM   */  
__declspec(naked) void func(int   *cr0,int   *cr2,int   *cr3)  
{
	_asm   {   
		push   ebp;
		mov   ebp,   esp  ;

		//;Issues   a   beep   to   show   that   you   can   do   direct   port   I/O  
		//;Not   a   good   piece   of   32-bit   code,   but   still   proves   the   fact  

		pushad  ;
		mov   ax,   1000  ;  
		mov   bx,   200  ;
		mov   cx,   ax  ;
		mov   al,   0b6h  ;
		out   43h,   al  ;
		mov   dx,   0012h  ;
		mov   ax,   34dch  ;
		div   cx  ;
		out   42h,   al  ;
		mov   al,   ah  ;
		out   42h,   al  ;
		in   al,   61h  ;
		mov   ah,   al  ;
		or   al,   03h  ;
		out   61h,   al  ;
l1:  
		mov   ecx,   4680  ;
l2:  
		loop   l2  ;
		dec   bx  ;
		jnz   l1  ;
		mov   al,   ah  ;
		out   61h,   al  ;
		popad  ;

		//;Save   away   the   registers   which   we   modify  
		push   esi  ;
		push   ebx  ;

		//;Get   the   contents   of   CR0,   CR2,   CR3   registers.   Check   if   PDWORDS   for   holding  
		//;CR0,   CR2,   CR3   are   not   NULL  
		//;More   strict   checking   needs   to   be   added   over   here   such   as   is   pointer    
		//;writable   etc,   since   if   junk   pointers   are   passed   to   this   function,  
		//;your   NT   machine   can   crash  
		//
		//;Get   the   first   paramter   from   EBP+0Ch,   since   this   function   is   called   via  
		//;a   far   call.  
		mov   esi,   [ebp+0Ch] ; 
		test   esi,   esi  ;
		jz   next  ;
		mov   ebx,   cr0  ;
		mov   [esi],   ebx  ;

next:  
		mov   esi,   [ebp+10h]  ;
		test   esi,   esi  ;
		jz   next1  ;
		mov   ebx,   cr2  ;
		mov   [esi],   ebx  ;

next1:  
		mov   esi,   [ebp+14h]  ;
		test   esi,   esi  ;
		jz   next2  ;
		mov   ebx,   cr3  ;
		mov   [esi],   ebx ; 

next2:  
		//;Restore   the   registers    
		pop   esi  ;
		pop   ebx  ;

		pop   ebp  ;

		//;Make   a   far   return.   Also   follow   the   _stdcall   calling   convention.  
		retf   0Ch  ;

	}  
}  

main()  
{  
	WORD   CallGateSelector;  
	int   rc;  
	short   farcall[3];  
	int   mcr0,   mcr2,   mcr3;  

	/*   Create   a   callgate   for   function   'func'   which   takes   '3'   parameters    
	and   get   the   callgate   selector   value   in   'CallGateSelector'*/  
	rc=CreateCallGate(func,   3,   &CallGateSelector);  

	/*   Check   if   callgate   creation   succeeds   */  
	if (rc==SUCCESS) {  
		printf("Selector   allocated   =   %x\n",   CallGateSelector);  

		/*Prepare   for   making   the   far   call.   Forget   about   the   offset    
		portion   of   far   call,   so   no   need   to   think   about   first   two  
		elements   of   farcall   array   */  
		farcall[2]=CallGateSelector;  
		_asm   {  
			/*Push   the   parameters   required*/  

			lea   esi,   mcr3  ;
			push   esi  ;
			lea   esi,   mcr2  ;
			push   esi  ;
			lea   esi,   mcr0  ;
			push   esi  ;

			/*Make   a   far   call*/  
			call   fword   ptr   [farcall]  ;
		}  

		/*   Print   the   contents   of   control   registers   */  
		printf("cr0=%x,   cr2=%x,   cr3=%x\n",   mcr0,   mcr2,   mcr3);  

		/*   Release   the   callgate   created   using   CreateCallGate*/  
		rc=FreeCallGate(CallGateSelector);  
		if   (rc!=SUCCESS)   {  
			printf("FreeCallGate   failed,   CallGateSelector=%x,   rc=%x\n",  
				CallGateSelector,   rc);  
		}  

	} else {  
		printf("CreateCallGate   failed,   rc=%x\n",   rc);  
	}  
	return   0;  
}   